package com.jinzhi.sms.sender;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.jinzhi.api.exception.IFastApiException;
import com.jinzhi.common.service.DictService;
import com.jinzhi.common.type.ApiEnumError;
import com.jinzhi.common.type.EnumErrorCode;
import com.jinzhi.common.utils.EhCacheUtil;
import com.jinzhi.jzapi.utils.RedisUtil;
import com.jinzhi.jzweb.domain.MessagefailsDO;
import com.jinzhi.jzweb.domain.MessagelogsDO;
import com.jinzhi.jzweb.service.MessagefailsService;
import com.jinzhi.jzweb.service.MessagelogsService;
import com.jinzhi.sms.config.AlyProperties;
import com.jinzhi.sms.support.SmsSender;
import com.jinzhi.sms.utils.MapToJsonStr;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 *
 * 阿里云短信
 */
@Slf4j
@Component
public class AlySender implements SmsSender {

    @Autowired
    private AlyProperties properties;
    @Autowired
    private MessagelogsService messagelogsService;
    @Autowired
    private MessagefailsService messagefailsService;
    @Autowired
    private RedisUtil redisUtil;

    /**
     * <pre>
     * 生成随机码
     * </pre>
     */
    public String getCode(){
        return new Random().nextInt(8999) + 1000 + "";
    }

    /**
     * String cacheName, String key, Object value, Integer timeToLiveSeconds
     * @param mobile
     * @param templateCode
     * @return
     */
    public boolean send(String mobile, String templateCode) {

        String codes=getCode();
        log.info("发送验证码为："+codes);
        try {

            EhCacheUtil.put(mobile+"code",codes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        boolean b=   redisUtil.set(mobile+ RedisUtil.code,codes,300);
        redisUtil.set(mobile,codes,10);

        Map templateParam = new HashMap();
        templateParam.put("code",codes);
        SendSmsResponse response1 =new SendSmsResponse();
        try {
            response1 = this.sendSms(mobile,templateCode,templateParam);
        } catch (ClientException e) {
            e.printStackTrace();
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return response1.getCode()!=null&&response1.getCode().equals("OK") ?true:false;
    }



    public SendSmsResponse sendSms(String mobile, String templateCode, Map templateParam) throws ClientException, JsonProcessingException {

        //可自助调整超时时间
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");

        //初始化acsClient,暂不支持region化
        IClientProfile profile = DefaultProfile.getProfile(properties.getProfile(), properties.getAccessKeyId(), properties.getAccessKeySecret());
        DefaultProfile.addEndpoint(properties.getProfile(), properties.getProfile(), properties.getProduct(), properties.getDomain());
        IAcsClient acsClient = new DefaultAcsClient(profile);

        //组装请求对象-具体描述见控制台-文档部分内容
        SendSmsRequest request = new SendSmsRequest();
        //必填:待发送手机号
        request.setPhoneNumbers(mobile);
        //必填:短信签名-可在短信控制台中找到
        request.setSignName(properties.getSignName());
        //必填:短信模板-可在短信控制台中找到
        request.setTemplateCode(templateCode);
        //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
        request.setTemplateParam(MapToJsonStr.conversion(templateParam));

        //选填-上行短信扩展码(无特殊需求用户请忽略此字段)
        //request.setSmsUpExtendCode("90997");

        //可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
        //request.setOutId("yourOutId");

        //hint 此处可能会抛出异常，注意catch
        SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);

        //插入日志
        MessagelogsDO messagelogsDO = new MessagelogsDO();
        messagelogsDO.setPhone(mobile);
        messagelogsDO.setState(sendSmsResponse.getCode());
        messagelogsDO.setSmsDemo(templateCode);
        messagelogsDO.setParameters(templateParam.toString());
        messagelogsDO.setPlatfromMsg(properties.getSignName());
        messagelogsService.insert(messagelogsDO);

        if (sendSmsResponse.getCode() != null && sendSmsResponse.getCode().equals("OK")) {
            log.info("【SMS】阿里云发送短信成功，code:{},message:{},requestId:{},bizId:{}", sendSmsResponse.getCode(), sendSmsResponse.getMessage(), sendSmsResponse.getRequestId(), sendSmsResponse.getBizId());
        }else {
            //插入失败日志，定时任务记录重发
            MessagefailsDO messagefailsDO = new MessagefailsDO();
            messagefailsDO.setErrorCode(sendSmsResponse.getCode());
            messagefailsDO.setErrorMsg(sendSmsResponse.getMessage());

//            Map<String,String> map = new HashMap<>();
//            map.put("name","短信重发次数");
//            map.put("type","smsFailsNum");
//            String sms_fails_num = dictService.selDicBy(map);
//            messagefailsDO.setAgains(Integer.parseInt(sms_fails_num));

            messagefailsDO.setAgains(0);//暂定默认为0
            messagefailsDO.setState(2);
            messagefailsService.insert(messagefailsDO);
            log.warn("【SMS】阿里云发送失败，code:{},message:{},requestId:{},bizId:{},mobile:{},signName:{},templateCode:{},templateParam:{}", sendSmsResponse.getCode(), sendSmsResponse.getMessage(), sendSmsResponse.getRequestId(), sendSmsResponse.getBizId(), mobile, properties.getSignName(), templateCode, templateParam);
            throw new IFastApiException(EnumErrorCode.apiSmsSendFailed.getCodeStr());
        }
        return sendSmsResponse;
    }


    @Override
    public void send(String mobile, String code, String templateCode) {
        Map templateParam = new HashMap();
        templateParam.put("code",code);
        this.send(mobile,templateCode,templateParam);
    }

    @Override
    public void send(String mobile, String templateCode, Map templateParam) {
        SendSmsResponse response;
        try {
            response = sendSms(mobile, templateCode, templateParam);
        } catch (ClientException e) {
            log.warn("【SMS】发送失败,手机号码：{}, 请求结果：{}", mobile, e);
            throw new IFastApiException(ApiEnumError.apiSmsSendFailed.getCodeStr());
        } catch (JsonProcessingException e) {
            log.warn("【SMS】参数转化错误,手机号码：{}, 请求结果：{}", mobile, e);
            throw new IFastApiException(ApiEnumError.parameterParseError.getCodeStr());
        }
        log.info("短信接口返回的数据----------------");
        log.info("Code=" + response.getCode());
        log.info("Message=" + response.getMessage());
        log.info("RequestId=" + response.getRequestId());
        log.info("BizId=" + response.getBizId());
    }

    @Override
    public void send(String mobile, String templateCode,String signName,Map messageContent) {
        if(StringUtils.isNotEmpty(mobile) && StringUtils.isNotEmpty(templateCode) && StringUtils.isNotEmpty(signName)
                && messageContent != null){
            this.sendSms(mobile,signName,templateCode,messageContent);
        }
    }

    /**
     * @param phoneNumbers 待发送手机号。支持以逗号分隔的形式进行批量调用，批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式；发送国际/港澳台消息时，接收号码格式为00+国际区号+号码，如“0085200000000”
     * @param signName 短信签名-可在短信控制台中找到
     * @param templateCode 短信模板-可在短信控制台中找到，发送国际/港澳台消息时，请使用国际/港澳台短信模版
     * @param templateParam 模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为"{\"name\":\"Tom\", \"code\":\"123\"}"
     * @throws IFastApiException
     */
    public void sendSms(String phoneNumbers, String signName, String templateCode, Map templateParam) {
        if(StringUtils.isBlank(properties.getAccessKeyId()) || StringUtils.isBlank(properties.getAccessKeySecret())
                || StringUtils.isBlank(phoneNumbers) || StringUtils.isBlank(signName) || StringUtils.isBlank(templateCode)
                || templateParam == null) {
            throw new IFastApiException(EnumErrorCode.apiSmsSendFailed.getCodeStr());
        }

        try {
            // 设置超时时间-可自行调整
            System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
            System.setProperty("sun.net.client.defaultReadTimeout", "10000");
            // 初始化ascClient,暂时不支持多region（请勿修改）
            IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", properties.getAccessKeyId(), properties.getAccessKeySecret());
            DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", properties.getProduct(), properties.getDomain());
            IAcsClient acsClient = new DefaultAcsClient(profile);
            // 组装请求对象
            SendSmsRequest request = new SendSmsRequest();
            // 使用post提交
            request.setMethod(MethodType.POST);
            // 必填:待发送手机号。支持以逗号分隔的形式进行批量调用，批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式；发送国际/港澳台消息时，接收号码格式为00+国际区号+号码，如“0085200000000”
           // String pgones="17373841816,18174630698";
            request.setPhoneNumbers(phoneNumbers);
            // 必填:短信签名-可在短信控制台中找到
            request.setSignName(signName);
            // 必填:短信模板-可在短信控制台中找到，发送国际/港澳台消息时，请使用国际/港澳台短信模版
            request.setTemplateCode(templateCode);
            // 可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
            // 友情提示:如果JSON中需要带换行符,请参照标准的JSON协议对换行符的要求,比如短信内容中包含\r\n的情况在JSON中需要表示成\\r\\n,否则会导致JSON在服务端解析失败
            request.setTemplateParam(MapToJsonStr.conversion(templateParam));
            // 可选-上行短信扩展码(扩展码字段控制在7位或以下，无特殊需求用户请忽略此字段)
            // request.setSmsUpExtendCode("90997");
            // 可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
            // request.setOutId("yourOutId");
            // 请求失败这里会抛ClientException异常
            SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);

            //插入日志
            MessagelogsDO messagelogsDO = new MessagelogsDO();
            messagelogsDO.setPhone(phoneNumbers);
            messagelogsDO.setState(sendSmsResponse.getCode());
            messagelogsDO.setSmsDemo(templateCode);
            messagelogsDO.setParameters(templateParam.toString());
            messagelogsDO.setPlatfromMsg(signName);
            messagelogsService.insert(messagelogsDO);

            if (sendSmsResponse.getCode() != null && sendSmsResponse.getCode().equals("OK")) {
                log.info("【SMS】阿里云发送短信成功，code:{},message:{},requestId:{},bizId:{}", sendSmsResponse.getCode(), sendSmsResponse.getMessage(), sendSmsResponse.getRequestId(), sendSmsResponse.getBizId());
            }else {
                //插入失败日志，定时任务记录重发
                MessagefailsDO messagefailsDO = new MessagefailsDO();
                messagefailsDO.setErrorCode(sendSmsResponse.getCode());
                messagefailsDO.setErrorMsg(sendSmsResponse.getMessage());

//                Map<String,String> map = new HashMap<>();
//                map.put("name","短信重发次数");
//                map.put("type","smsFailsNum");
//                String sms_fails_num = dictService.selDicBy(map);
//                messagefailsDO.setAgains(Integer.parseInt(sms_fails_num));
                messagefailsDO.setAgains(0);//暂定默认为0
                messagefailsDO.setState(2);
                messagefailsService.insert(messagefailsDO);
                log.warn("【SMS】阿里云发送失败，code:{},message:{},requestId:{},bizId:{},mobile:{},signName:{},templateCode:{},templateParam:{}", sendSmsResponse.getCode(), sendSmsResponse.getMessage(), sendSmsResponse.getRequestId(), sendSmsResponse.getBizId(), phoneNumbers, signName, templateCode, templateParam);
                throw new IFastApiException(EnumErrorCode.apiSmsSendFailed.getCodeStr());
            }
        }catch (Exception e) {
            log.warn("【SMS】阿里云发送短信失败:{},mobile:{},signName:{},templateCode:{},templateParam:{}", e.getMessage(), phoneNumbers, signName, templateCode, templateParam);
            throw new IFastApiException(EnumErrorCode.apiSmsSendFailed.getCodeStr());
        }
    }

//    public static void main(String[] args) {
//        String phoneNumbers = "18175137287,15581635820";
//        String templateCode = "SMS_182385250";
//        Map templateParam = new HashMap();
//        templateParam.put("code","3572");
//        sendSms(phoneNumbers, templateCode, templateParam);
//    }

}
